/*
 * Copyright (c) 2010-2011, Petr Panteleyev <petr@panteleyev.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.livejournal;

import com.google.common.collect.ImmutableList;
import java.awt.BorderLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.SwingUtilities;
import org.panteleyev.blogclient.BloggerEditorFrame;
import org.panteleyev.blogclient.HandleExceptionEDT;
import org.panteleyev.blogclient.Options;
import org.panteleyev.blogclient.UserProfileManager;
import org.panteleyev.blogclient.photo.ThumbnailPanel;
import org.panteleyev.fotobilder.FBAccount;
import org.panteleyev.fotobilder.FBGallery;
import org.panteleyev.fotobilder.FBPicture;
import org.panteleyev.swing.ClipboardUtil;
import org.panteleyev.swing.MenuProvider;
import org.panteleyev.swing.OSUtil;
import org.panteleyev.swing.SwingFactory;
import org.panteleyev.swing.ToolBarProvider;
import org.panteleyev.swing.filefilters.ImageFileFilter;
import org.panteleyev.utilities.Updatable;

/**
 *
 * @author Petr Panteleyev <petr@panteleyev.org>
 */
final class FotoBilderGalleryPanel extends ThumbnailPanel<FotoBilderFrame,FBPicture> implements Updatable, MenuProvider, ToolBarProvider {
    private LJUserProfile               profile;
    private FBAccount                   fbAccount;
    private FBGallery                   gallery;
    private AbstractAction              uploadPictureAction;
    private AbstractAction              pictureOpenWebAction = new PictureOpenWebAction();
    private AbstractAction              picturePublishAction = new PublichPucturesAction();
    private PicturePropertiesAction     picturePropertiesAction = new PicturePropertiesAction();
    private ArrayList<AbstractAction>   toolbarActions = new ArrayList<AbstractAction>();

    private static final JFileChooser   graphicsFileChooser;

    @Override
    protected int getCellWidth() {
        return 110;
    }

    @Override
    protected void pictureDoubleClicked(FBPicture picture) {
        onOpenPicture();
    }

    private final class PictureUploadThread extends Thread {
        private File[] files;

        PictureUploadThread(File[] files) {
            this.files = files;
            startLongOperation();
        }

        @Override
        public void run() {
            try {
                ArrayList<FBPicture> pictures = fbAccount.uploadPictures(gallery, files);
                for (FBPicture pict : pictures) {
                    fbAccount.addPicture(gallery, pict);
                }
                getProfile().storePictures(fbAccount);
                update();
            } catch (Exception ex) {
                SwingUtilities.invokeLater(new HandleExceptionEDT(getFrame(), ex));
            } finally {
                finishLongOperation();
            }
        }
    }

    private class UpdatePhotosThread extends Thread {
        UpdatePhotosThread() {
            startLongOperation();
        }

        @Override
        public void run() {
            try {
                setPictures(fbAccount.getPicturesForGallery(gallery));
                updateThumbnails();
            } catch (Exception ex) {
                SwingUtilities.invokeLater(new HandleExceptionEDT(getFrame(), ex));
            } finally {
                finishLongOperation();
            }
        }

        private void updateThumbnails() throws IOException {
            getThumbnails().clear();
            getThumbnails().ensureCapacity(getPictures().size());

            for (FBPicture pict : getPictures()) {
                final URL url = new URL(pict.getURLString() + "/s100x100");
                ImageIcon thumb = UserProfileManager.loadThumbnail(profile, url);

                if (thumb == null) {
                    final URLConnection conn = url.openConnection();
                    try {
                        BufferedImage bim = ImageIO.read(conn.getInputStream());
                        thumb = new ImageIcon(bim);
                        UserProfileManager.storeThumbnail(profile, url, bim);
                    } catch (IOException ex) {
                        // Unknown error, nothing to do here
                    }
                }
                getThumbnailsLock().lock();
                try {
                    getThumbnails().add(thumb);
                } finally {
                    getThumbnailsLock().unlock();
                }
                SwingUtilities.invokeLater(getUpdateWindowEDT());
            }
        }
    }

    public FotoBilderGalleryPanel(FotoBilderFrame frame, LJUserProfile profile, FBGallery gallery) {
        super(frame);
        this.profile = profile;
        fbAccount = profile.getFbAccount();
        this.gallery = gallery;

        createActions();
        initComponents();

        update();
    }

    private LJUserProfile getProfile() {
        return profile;
    }

    FBGallery getGallery() {
        return gallery;
    }

    private void initComponents() {
        setLayout(new BorderLayout());

        add(getScroller(), BorderLayout.CENTER);
        getScroller().setComponentPopupMenu(createMenu().getPopupMenu());
        Options.getBounds(this);
    }

    public int getGalleryID() {
        return gallery.getID();
    }

    private void onOpenPicture() {
        FBPicture picture = getSelectedPicture();
        if (picture != null) {
            OSUtil.runBrowser(picture.getURLString());
        }
    }

    private void createActions() {
        uploadPictureAction = new PictureUploadAction();
        toolbarActions.add(uploadPictureAction);
        toolbarActions.add(pictureOpenWebAction);
    }

    @Override
    protected void onPublishPictures(ImmutableList<FBPicture> selectedPictures) {
        if (selectedPictures.size() == 0) {
            return;
        }

        final PicturePublishDialog dial = new PicturePublishDialog(getFrame());
        if (dial.showDialog()) {
            final StringBuilder b = new StringBuilder();

            final int colCount = dial.getColumnCount();
            final boolean fullSize = dial.getFullSize();
            final boolean linkToSource = dial.getLinkToSource();
            final String smallSizeS = dial.getSmallSize();
            final boolean annotate = dial.getAnnotate();
            final boolean border = dial.getBorder();

            if (dial.isUseTable()) {
                b.append("<table border=\"0\">\n");
            }

            int col = colCount;
            for (FBPicture pict : selectedPictures) {
                if (pict != null) {
                    if (col == colCount && dial.isUseTable()) {
                        b.append("<tr>\n");
                    }

                    if (dial.isUseTable()) {
                        b.append("<td>");
                    }

                    if (fullSize) {
                        b.append(pict.generateImageLink());
                    } else {
                        if (linkToSource) {
                            b.append(String.format("<a href=\"%s\">", pict.getURLString()));
                        }

                        b.append(String.format("<img src=\"%s/s%sx%s\" border=\"%d\">",
                            pict.getURLString(),
                            smallSizeS,
                            smallSizeS,
                            (border)? 1 : 0
                        ));

                        if (linkToSource) {
                            b.append("</a>");
                        }

                    }

                    if (annotate && (pict.getTitle().length() != 0)) {
                        b.append("<br>");
                        b.append(pict.getTitle());
                    }

                    if (dial.isUseTable()) {
                        b.append("</td>\n");
                    } else {
                        b.append("\n");
                    }

                    if (--col == 0) {
                        col = colCount;
                        if (dial.isUseTable()) {
                            b.append("</tr>\n");
                        }
                    }
                }
            }

            if (col != colCount && dial.isUseTable()) {
                b.append("</tr>\n");
            }
            if (dial.isUseTable()) {
                b.append("</table>\n");
            }

            BloggerEditorFrame<?> wnd = dial.getDestinationWindow();
            if (wnd == null) {
                ClipboardUtil.put(b.toString());
            } else {
                wnd.getEditor().insertText(b.toString());
            }
        }
    }

    @Override
    protected void onUpload() {
        if (graphicsFileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            File[] files = graphicsFileChooser.getSelectedFiles();
            new PictureUploadThread(files).start();
        }
    }

    @Override
    public void update() {
        new UpdatePhotosThread().start();
    }

    protected void startLongOperation() {
        getFrame().startLongOperation();
        uploadPictureAction.setEnabled(false);
        pictureOpenWebAction.setEnabled(false);
        picturePublishAction.setEnabled(false);
    }

    protected void finishLongOperation() {
        uploadPictureAction.setEnabled(true);
        pictureOpenWebAction.setEnabled(true);
        picturePublishAction.setEnabled(true);
        getFrame().finishLongOperation();
    }

    @Override
    protected void onPictureProperties(FBPicture picture) {
        new PicturePropertiesDialog(getFrame(), picture).showDialog();
    }

    @Override
    public JMenu createMenu() {
        return SwingFactory.createMenu(PHOTO_MENU_NAME,
                picturePropertiesAction,
                null,
                picturePublishAction,
                null,
                pictureOpenWebAction,
                uploadPictureAction);
    }

    @Override
    public Collection<AbstractAction> getToolBarActions() {
        return toolbarActions;
    }

    static {
        graphicsFileChooser = new JFileChooser();
        graphicsFileChooser.setAcceptAllFileFilterUsed(false);
        graphicsFileChooser.setDialogTitle("Upload Pictures");
        graphicsFileChooser.setMultiSelectionEnabled(true);

        graphicsFileChooser.addChoosableFileFilter(new ImageFileFilter());
    }

}
